Skip to content

[Backport v8] Support wildcard values for content scope dimensions - #6292

Merged
VPS-thodax merged 1 commit into
v8.x.xfrom
claude/backport-v8-6114
Sep 8, 2026
Merged

[Backport v8] Support wildcard values for content scope dimensions#6292
VPS-thodax merged 1 commit into
v8.x.xfrom
claude/backport-v8-6114

Conversation

@VPS-thodax

Copy link
Copy Markdown
Contributor

Backport of #6114 to v8.x.x.

Original description

Problem

Content scopes could only grant access to concrete dimension values that are part of availableContentScopes. There was no way to grant a user access to any value of a single dimension (e.g. every language within a domain, or every product) without enumerating all values — which is not feasible for dimensions with many (potentially thousands) of values.

Solution

getContentScopesForUser can now use the wildcard value "*" as the value of a single content scope dimension to grant access to any value for that dimension. The wildcard is matched during the content scope check, so it does not need to be part of availableContentScopes.

For users with access to all content scopes, currentUser.permissions[].contentScopes now returns a single wildcard scope (e.g. [{ domain: "*", language: "*" }]) instead of the enumerated availableContentScopes. The default isAllowed and currentUser.allowedContentScopes handle the wildcard; a custom isAllowed must treat "*" as matching any value of a dimension.

Backport notes

Cherry-picking the squash commit (a00f0b2ed6bed7a53b0aad6c5c31f41aa19e1f39) from main produced conflicts in packages/api/cms-api/src/user-permissions/access-control.service.ts and packages/api/cms-api/src/warnings/warning.resolver.ts, both resolved by applying the incoming change on top of v8.x.x's existing code (an older checkContentScope helper replaced by the new isScopeWithin helper, and an import path difference from a later entity-info directory move on main that isn't part of v8.x.x).

Verification

  • @comet/cms-api and @comet/cms-admin: build, lint (prettier/eslint/tsc) pass.
  • demo/api: lint (api-generator regeneration + prettier/eslint/tsc) passes, generated files unchanged.
  • packages/api/cms-api unit tests for access-control.service pass.
  • demo/api AppModule initializes correctly via pnpm run console --help (schema/block-meta regenerate); it only fails afterwards on connecting to Postgres, since the full Docker demo could not be started in this sandbox — Docker Hub image pulls are blocked by the environment's network policy (403 from CloudFront).

🤖 Generated with Claude Code

https://claude.ai/code/session_01B37BzfVeTSW2Kn9Qgvtd1v


Generated by Claude Code

## Problem

Content scopes could only grant access to concrete dimension values that
are part of `availableContentScopes`. There was no way to grant a user
access to any value of a single dimension (e.g. every language within a
domain, or every product) without enumerating all values — which is not
feasible for dimensions with many (potentially thousands) of values.

## Solution

`getContentScopesForUser` can now use the wildcard value "*" as the value
of a single content scope dimension to grant access to any value for that
dimension. The wildcard is matched during the content scope check, so it
does not need to be part of `availableContentScopes`.

For users with access to all content scopes,
`currentUser.permissions[].contentScopes` now returns a single wildcard
scope instead of the enumerated `availableContentScopes`. The default
`isAllowed` and `currentUser.allowedContentScopes` handle the wildcard; a
custom `isAllowed` must treat "*" as matching any value of a dimension.

(cherry picked from commit a00f0b2)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B37BzfVeTSW2Kn9Qgvtd1v
@VPS-thodax VPS-thodax self-assigned this Sep 2, 2026
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 2d54b6e6-d032-4194-89db-23ec7787e094

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@VPS-thodax
VPS-thodax disabled the stack merge September 7, 2026 14:29
@VPS-thodax
VPS-thodax merged commit ea11743 into v8.x.x Sep 8, 2026
5 checks passed
@VPS-thodax
VPS-thodax deleted the claude/backport-v8-6114 branch September 8, 2026 07:34
VPS-thodax added a commit that referenced this pull request Sep 8, 2026
)

Backport of #6115 to `v8.x.x`.

> [!NOTE]
> This PR is stacked on #6292 (the backport of #6114 to `v8.x.x`, layer
1). It targets `claude/backport-v8-6114` because `v8.x.x` doesn't have
the wildcard content scope dimension support (#6114) yet. Once #6292 is
merged into `v8.x.x`, this PR's base will need to be retargeted to
`v8.x.x` (or GitHub will do so automatically once #6292 merges, matching
how the original stacked PRs behaved).

## Original description

### Problem

Content scope dimensions were only known implicitly from the keys of the
`availableContentScopes` values. An optional dimension that is not part
of `availableContentScopes` (e.g. one with too many values to enumerate)
therefore had no runtime representation at all — it could neither be
declared nor used with arbitrary values.

### Solution

Add an optional `availableContentScopeDimensions` option to the
`UserPermissionsModule` to declare the content scope dimensions (with
optional labels) at runtime. When omitted, the dimensions are derived
from the keys of `availableContentScopes` as before, so existing apps
are unaffected. The declared dimensions are used to represent access to
all content scopes as a per-dimension wildcard (`{ domain: "*", ... }`),
which therefore also covers dimensions that are not part of
`availableContentScopes`.

A content scope for a dimension that is not part of
`availableContentScopes` may now hold any value (including the `"*"`
wildcard).

#### Removing `checkContentScopes`

Content scopes are no longer validated against `availableContentScopes`
(the `checkContentScopes` method is removed) — see the original PR
(#6115) for the full rationale.

## Backport notes

Cherry-picking the squash commit
(`f4d091fa71ffe1c3c0f72431bbdb6151b6e93faa`) from `main` onto
`claude/backport-v8-6114` produced conflicts in two files, both resolved
by applying the incoming change against `v8.x.x`'s existing code:

-
`packages/api/cms-api/src/user-permissions/user-content-scopes.resolver.ts`:
the incoming code used `userService.findUserOrThrow(userId)`, but
`findUserOrThrow` doesn't exist on `v8.x.x` (it was introduced by a
later, unrelated `main` commit). Kept using `v8.x.x`'s existing
`userService.getUser(userId)` instead, combined with the new
`filterContentScopesForUser` (already present via #6114's backport).
- `demo/api/src/content-scope/content-scope.interface.ts`: module
augmentation naming conflict (`@dextinity/cms-api` vs. `@comet/cms-api`,
matching `v8.x.x`'s pre-rename package naming — see #6280 for
precedent). Kept `@comet/cms-api` and added the new `product` dimension.

Also converted the cherry-picked `user-permissions.service.spec.ts` from
`vitest` to `jest` (matching `@comet/cms-api`'s test runner on this
branch — same adjustment as #6144/#6280), and updated the changeset
package name from `@dextinity/cms-api` to `@comet/cms-api` (per the
pre-rename naming convention, per the routine's own caveat).

## Verification

- `@comet/cms-api`: build, lint (prettier/eslint/tsc) pass.
- `@comet/cms-api` full test suite: 204/204 passing, including the 7 new
tests for
`getAvailableContentScopeDimensions`/`filterContentScopesForUser`.
- `demo/api`: `api-generator` regenerates cleanly with no diff to the
generated files; lint (prettier/eslint/tsc) passes.
- `demo/api` `AppModule`/`GraphQLModule` initialize correctly via `pnpm
run console --help` (schema/block-meta regenerate); it only fails
afterwards on connecting to Postgres, since the full Docker demo could
not be started in this sandbox — Docker Hub image pulls are blocked by
the environment's network policy (403 from CloudFront), consistent with
the same limitation noted on prior v8 backport PRs (e.g. #6280, #6292).
Please verify the runtime-declared content scope dimensions manually
before merging.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01DeZZCJgNydRxnbPuRBkTjp

---
_Generated by [Claude
Code](https://claude.ai/code/session_01DeZZCJgNydRxnbPuRBkTjp)_

Co-authored-by: Claude <noreply@anthropic.com>
VPS-thodax added a commit that referenced this pull request Sep 8, 2026
## Problem

The release workflow on `v8.x.x` fails when assembling the release plan:

> 🦋 error Error: Found changeset user-permissions-wildcard-content-scope
for package @dextinity/cms-api which is not in the workspace

No release can be published from `v8.x.x` until this is resolved.

## Cause

`.changeset/user-permissions-wildcard-content-scope.md` was backported
from a branch where the packages are already published under the
`@dextinity/*` scope. On `v8.x.x` they still use `@comet/*`, so
`@dextinity/cms-api` does not exist in the workspace and Changesets
aborts.

**This is the second time the same mistake blocks the v8 release, and it
happened despite the backport routine explicitly warning about it.**
#6293 fixed the identical break for `olive-pears-invent` less than a
week ago. The routine carries a caveat about adjusting the changeset
scope when backporting to `v8.x.x` — #6318 followed it and renamed its
changeset, but #6292, which added this one, did not. A caveat in the
prompt is evidently not enough: the routine needs a check that fails the
backport when a changeset names a package that isn't in the target
branch's workspace.

## Fix

Rename the packages in the changeset's frontmatter to `@comet/cms-api`
and `@comet/cms-admin`, matching the names in
`packages/api/cms-api/package.json` and
`packages/admin/cms-admin/package.json` on this branch. The changeset
text is unchanged, so the released changelog entry stays the same.

## Verification

`changeset status` cannot run on this branch (it resolves changed
packages against a `main` base ref that doesn't apply here), so the
release plan was assembled directly via `@changesets/get-release-plan`.
It now succeeds and versions 19 packages from `8.31.0` to `8.32.0`,
consuming both pending changesets.

## Further information

- Failing run:
https://github.com/vivid-planet/dextinity/actions/runs/34201879258
- Previous occurrence and fix: #6293
- Backport that added this changeset: #6292 (the sibling backport #6318
did rename its changeset)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_017d1A8MxYTpS29HTXgKJpJA

---
_Generated by [Claude
Code](https://claude.ai/code/session_017d1A8MxYTpS29HTXgKJpJA)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants